package Library;

import java.rmi.*;
import java.rmi.registry.*;

/**
 * Abstracte klasse waarmee een RMIServer gebouwd kan worden.
 * Deze klasse is NonSerializable.
 */
public abstract class RMIServer extends Thread
{
    /**
     * Constructor voor het aanmaken van een RMIServer.
     * @param port poort waarop de server draait.
     */
    public RMIServer(int port)
    {
        m_Port = port;
        if (System.getSecurityManager() == null)
        {
            // Stel de securitymanager in
            System.setProperty( "java.security.policy","c:\\RISK.policy");
            System.setSecurityManager ( new RMISecurityManager() );           
        }
    }
    
    private transient Registry m_Reg;
    
    /**
     * Stopt de Server.
     */
    public void stopServer()
    {
        setRunning(false);
    }
    
    /**
     *
     */
    protected int m_Port;
    /**
     * Start de Server.
     * @return succesvol
     */
    public boolean startServer()
    {
        //NOTE: we need to wait until server has booted RMI
        //This might take a while, we're waiting 30 seconds and each time we check it's state.
        start();
        for (int t = 0; t < 30; t++)  
        {
          try  
          {
              sleep(1000);
          }
          catch (InterruptedException ex)
          {
              System.out.println("Warning: Server can't call 'sleep'. Server Still Running.");
          }
          
          // Check if RMI has booted.
          if (getRunning())
              return true;  
        }
        
        // Our final try, if RMI has booted we'll return true, else return false.
        return getRunning();  
    }
    
    /**
     *
     */
    protected boolean m_Running = false;
    /**
     *
     */
    protected final Object m_Mutex = new Object();
    /**
     * Veilige Methode om aan te geven dat de Server Draait.
     * @param value 
     */
    protected void setRunning(boolean value)
    {
        synchronized (m_Mutex)
        {
            m_Running = value;
        }
    }
    
    /**
     * Veilige methode om op te vragen of de server Draait.
     * @return 
     */
    protected boolean getRunning()
    {
        boolean returnValue;
        synchronized (m_Mutex)
        {
            returnValue = m_Running;
        }
        return returnValue;
    }
    
    /**
     * Veilige Methode om een Object op de Server te Hosten.
     * @param name naam waaronder het object gehost wordt
     * @param object object dat gehost wordt
     * @throws RemoteException onbekende RMI fout, bijv. RMI niet gestart.
     * @throws AlreadyBoundException object is reeds gehost
     */
    public void HostObject(String name, Remote object) throws RemoteException, AlreadyBoundException
    {
        if (getRunning())
            m_Reg.bind(name, object);
    }
    
    /**
     * Deze methode zorgt ervoor dat de Server blijft draaien.
     */
    @Override
    public void run()
    {
        try
        {
            m_Reg = LocateRegistry.createRegistry(m_Port);
        }
        catch (RemoteException ex)
        {
            ex.printStackTrace();
        }
        
        if (m_Reg != null)
        {
            // Prepare Thread
            setRunning(true);
            
            // Thread Loop
            while (getRunning())
            {
                try
                {
                    sleep(100);
                }
                catch (InterruptedException ex)
                {
                    setRunning(false);
                    System.out.println("Error: Server can't call 'sleep'. Server Stopped.");
                }
            }
            
            // Disposal/Exit Thread
            m_Reg = null;
        }
    }
}
